home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Think Class Libraries / CScrollorama 1.1 / CScrollorama.c next >
Encoding:
Text File  |  1994-11-30  |  19.7 KB  |  831 lines  |  [TEXT/KAHL]

  1. /*
  2.  * CScrollorama.c
  3.  *
  4.  * A panorama, with a few features affixed.
  5.  *
  6.  * © Copyright 1992 by Jamie R. McCarthy.  All rights reserved.
  7.  * This code can be both distributed and used freely.
  8.  * Internet: k044477@kzoo.edu            AppleLink: j.mccarthy
  9.  * Telephone:  800-421-4157 or US 616-665-7075 (9:00-5:00 Eastern time)
  10.  * I'm releasing this code with the hope that someone will get
  11.  * something out of it.  Feedback of any sort, even just letting
  12.  * me know that you're using it, is greatly appreciated!
  13.  *
  14.  * This class was made to be hacked up and stolen from.  I don't
  15.  * imagine you'll want to use all four features of CScrollorama
  16.  * in exactly the way I've implemented them.  But you're welcome
  17.  * to cut'n'paste together your own subclass of CPanorama.
  18.  *
  19.  *
  20.  *                                FOUR FABULOUS FEATURES
  21.  *
  22.  * THE FIRST FEW FEATURES
  23.  *
  24.  * 1:  CScrollorama::Scroll() doesn't call _ScrollRect, so the
  25.  * scrolled region doesn't get quickly painted white or whatever the
  26.  * background pattern is.  Instead, it just leaves that part alone.
  27.  * (If the redraw argument is TRUE, of course, it will redraw it
  28.  * immediately;  otherwise, it will wait till the next update event.)
  29.  *
  30.  * 2:  A CScrollorama won't let you scroll the frame past a given
  31.  * margin around the bounds.  If you use a CPanorama in a CScrollPane,
  32.  * the scroll pane will protect you from doing this (check out
  33.  * CScrollPane::DoHorizScroll and CScrollPane::DoVertScroll).  But
  34.  * if you're using a "naked" CPanorama, you have no such protection
  35.  * unless you do something like CScrollorama does.  The default
  36.  * margin is zero pixels on each side.  Note that you'll probably
  37.  * want to specify negative values for top and left, positive ones
  38.  * for bottom and right.
  39.  * 
  40.  * 3:  CScrollorama includes Mårten Sörliden's SetBounds() bug fix.
  41.  *
  42.  * THE FOURTH FEATURE
  43.  *
  44.  * OK, first comes a definition.  "Avoided" is my term for a
  45.  * region of a pane which will not be drawn into by its
  46.  * _immediate_enclosure_.
  47.  *
  48.  * A CScrollorama may have its aperture, or any subregion of it,
  49.  * avoided (by its enclosure's Draw() method), clipped (for its
  50.  * own Draw() method), or both, or neither.
  51.  *
  52.  * For example, if you want your pane that draws Kilimanjaro to
  53.  * enclose your pane that draws a leopard, and you don't want an
  54.  * ugly white blank rectangle around the leopard, you would tell
  55.  * Kilimanjaro to avoid the leopard, and then set the leopard's
  56.  * avoided region to something leopard-shaped.  Then, when
  57.  * Kilimanjaro draws, it will leave a leopard-shaped hole, which
  58.  * the leopard pane will subsequently draw into.  But let's say
  59.  * your leopard-drawing routine just copies a rectangle (with a
  60.  * leopard in it) onto the screen anyway;  in that case, a
  61.  * leopard-shaped hole doesn't help.  So you also need to set
  62.  * the leopard pane to clip _itself_ to that same region.  Then
  63.  * Kilimanjaro will draw everywhere _but_ in the leopard, the
  64.  * leopard will draw _only_ in the leopard, and everyone will
  65.  * be happy (except the leopard, who will shortly freeze).
  66.  *
  67.  * Or, if you had ten concentric panes, each forming one ring
  68.  * of a bullseye by calling PaintOval(), the TCL would just draw
  69.  * one over the other.  This means the center pane would flash
  70.  * ten times.  To make each pane draw a ring not a circle,
  71.  * thereby removing the "flashing center" effect, you would set
  72.  * each one's avoided region to the circle that it draws.
  73.  *
  74.  * By default, a scrollorama will avoid all subpanes which are
  75.  * also CScrolloramas.  You can tell it not to do this--i.e. to
  76.  * revert to typical TCL pane behavior--by calling
  77.  * setAvoidSubscrolloramas(FALSE).  If you want a particular
  78.  * scrollorama to not be avoided, call setBeAvoided(FALSE).
  79.  *
  80.  * By default, a scrollorama's avoided region is a "wide-open"
  81.  * region.  (The avoided region applies to the bounds, not the
  82.  * frame.  It's expressed in frame coordinates--pixels--but as
  83.  * the frame moves over the bounds, the avoided region "sticks"
  84.  * to the contents of the pane.  The actual clipping region at
  85.  * the time of drawing will be the intersection of the avoided
  86.  * region and the avoided pane's aperture.)  To change it, call
  87.  * setAvoidedRgn().
  88.  *
  89.  * By default, a scrollorama does _not_ clip itself to the
  90.  * avoided region.  If you would like it to do so, call
  91.  * setClipToAvoidedRgn(TRUE).
  92.  *
  93.  * Note that it is possible to have an avoided region going
  94.  * to waste.  A region that's neither being avoided nor being
  95.  * clipped-to might as well not be there.  To release its
  96.  * memory, call setAvoidedRgn(NULL).  This returns the avoided
  97.  * region to wide-open.
  98.  *
  99.  * Note also that a scrollorama with an empty avoided region,
  100.  * that clips drawing to that region, is essentially hidden.
  101.  * It's more efficient just to Hide() the pane, though.
  102.  *
  103.  * Note, thirdly, that a scrollorama can only avoid its
  104.  * immediate subscrolloramas, not subsubscrolloramas or
  105.  * subsubsubscrolloramas.  If you have, say, a Kilimanjaro pane
  106.  * enclosing a leopard pane enclosing a "flea" pane, and you
  107.  * tell the leopard to setBeAvoided(FALSE), then there's no way
  108.  * to tell Kilimanjaro to avoid the flea.  If this discrepancy
  109.  * gets under your skin, let me know and I'll consider
  110.  * implementing recursive avoidance.
  111.  *
  112.  */
  113.  
  114.  
  115.  
  116. /********************************/
  117.  
  118. #include "CScrollorama.h"
  119.  
  120. /********************************/
  121.  
  122. #include <CList.h>
  123. #include <CWindow.h>
  124.  
  125. /********************************/
  126.  
  127. extern RgnHandle gUtilRgn;
  128.  
  129. /********************************/
  130.  
  131. void nonErasingScrollRect(Rect *srcArea, short hDelta, short vDelta, RgnHandle updateRgn);
  132.  
  133. /********************************/
  134.  
  135.  
  136.  
  137. void CScrollorama::IScrollorama(CView *anEnclosure, CBureaucrat *aSupervisor,
  138.     short aWidth, short aHeight,
  139.     short aHEncl, short aVEncl,
  140.     SizingOption aHSizing, SizingOption aVSizing)
  141. {
  142.     showMargin.left =
  143.         showMargin.top =
  144.         showMargin.right =
  145.         showMargin.bottom = 0;
  146.     
  147.     inherited::IPanorama(anEnclosure, aSupervisor,
  148.         aWidth, aHeight,
  149.         aHEncl, aVEncl,
  150.         aHSizing, aVSizing);
  151.     
  152.     IScrolloramaX();
  153. }
  154.  
  155.  
  156.  
  157. void CScrollorama::IViewTemp(CView *anEnclosure, CBureaucrat *aSupervisor,
  158.     Ptr viewData)
  159. {
  160.     showMargin.left =
  161.         showMargin.top =
  162.         showMargin.right =
  163.         showMargin.bottom = 0;
  164.     
  165.     inherited::IViewTemp(anEnclosure, aSupervisor, viewData);
  166.     
  167.     IScrolloramaX();
  168. }
  169.  
  170.  
  171.  
  172. void CScrollorama::IScrolloramaX(void)
  173. {
  174.     paneVisRgn = NULL;
  175.     pvrIsUpToDate = TRUE;
  176.     
  177.         /*
  178.          * By default, avoid all subscrolloramas.
  179.          */
  180.     avoidSubscrolloramas = TRUE;
  181.     
  182.         /*
  183.          * By default, if the enclosing pane is a scrollorama that wants to
  184.          * avoid drawing over me, then let it avoid drawing over me.
  185.          */
  186.     beAvoided = TRUE;
  187.     
  188.         /*
  189.          * By default, don't clip my drawing to my avoided region.
  190.          */
  191.     clipToAvoidedRgn = FALSE;
  192.     
  193.         /*
  194.          * By default, if the enclosing pane wants to avoid this pane,
  195.          * then it should avoid the whole aperture of this pane.
  196.          */
  197.     avoidedRgn = NULL;
  198. }
  199.  
  200.  
  201. void CScrollorama::Dispose(void)
  202. {
  203.     if (beAvoided
  204.         && member(itsEnclosure, CScrollorama)
  205.         && ((CScrollorama*)itsEnclosure)->getAvoidSubscrolloramas()) {
  206.         
  207.         ((CScrollorama*)itsEnclosure)->markPaneVisRgnAsOutOfDate();
  208.         
  209.     }
  210.     
  211.     forgetPaneVisRgn();
  212.     forgetAvoidedRgn();
  213.     inherited::Dispose();
  214. }
  215.  
  216.  
  217.  
  218. void CScrollorama::setShowMargin(LongRect *newShowMargin)
  219. {
  220.     showMargin = *newShowMargin;
  221. }
  222.  
  223.  
  224.  
  225. void CScrollorama::getShowMargin(LongRect *theShowMargin)
  226. {
  227.     *theShowMargin = showMargin;
  228. }
  229.  
  230.  
  231.  
  232. void CScrollorama::setShowBounds(register LongRect *newShowBounds)
  233. {
  234.     LongRect newShowMargin;
  235.     newShowMargin.top = newShowBounds->top - bounds.top;
  236.     newShowMargin.left = newShowBounds->left - bounds.left;
  237.     newShowMargin.right = newShowBounds->right - bounds.right;
  238.     newShowMargin.bottom = newShowBounds->bottom - bounds.bottom;
  239.     setShowMargin(&newShowMargin);
  240. }
  241.  
  242.  
  243.  
  244. void CScrollorama::getShowBounds(register LongRect *theShowBounds)
  245. {
  246.     theShowBounds->top = bounds.top + showMargin.top;
  247.     theShowBounds->left = bounds.left + showMargin.left;
  248.     theShowBounds->right = bounds.right + showMargin.right;
  249.     theShowBounds->bottom = bounds.bottom + showMargin.bottom;
  250. }
  251.  
  252.  
  253.  
  254. void CScrollorama::Scroll(long hDelta, long vDelta, Boolean redraw)
  255. {
  256.     LongRect theShowBounds;
  257.     register long hPixelDelta, vPixelDelta;
  258.     Rect scrollArea;
  259.     
  260.     
  261.         /*
  262.          * The first feature:  contained scrolling.
  263.          */
  264.         
  265.     getShowBounds(&theShowBounds);
  266.     if (frame.left + hDelta < theShowBounds.left)
  267.         hDelta = theShowBounds.left - frame.left;
  268.     if (frame.right + hDelta > theShowBounds.right)
  269.         hDelta = theShowBounds.right - frame.right;
  270.     if (frame.top + vDelta < theShowBounds.top)
  271.         vDelta = theShowBounds.top - frame.top;
  272.     if (frame.bottom + vDelta > theShowBounds.bottom)
  273.         vDelta = theShowBounds.bottom - frame.bottom;
  274.     if (hDelta == 0 && vDelta == 0) return;
  275.     
  276.     
  277.         /*
  278.          * Do the actual scroll.
  279.          */
  280.         
  281.     hPixelDelta = hDelta * hScale;
  282.     vPixelDelta = vDelta * vScale;
  283.     
  284.     if (redraw) {
  285.         if ( Abs(hPixelDelta)<width && Abs(vPixelDelta)<height ) {
  286.                 /*
  287.                  * If some of what's presently visible will still be visible
  288.                  * after we scroll, save that part.
  289.                  */
  290.             Prepare();
  291.             FrameToQDR(&aperture, &scrollArea);
  292.                 /*
  293.                  * The second feature:  non-flashing scrolling.
  294.                  */
  295.             nonErasingScrollRect(&scrollArea, -hPixelDelta, -vPixelDelta, gUtilRgn);
  296.             InvalRgn(gUtilRgn);
  297.         } else {
  298.                 /*
  299.                  * Otherwise, the whole aperture has to be redrawn.
  300.                  */
  301.             Refresh();
  302.         }
  303.     }
  304.     
  305.     
  306.         /*
  307.          * Take care of the instance variables that have to be updated.
  308.          */
  309.     
  310.     position.h += hDelta;
  311.     position.v += vDelta;
  312.     
  313.     hOrigin += hPixelDelta;
  314.     vOrigin += vPixelDelta;
  315.     
  316.     ForceNextPrepare();
  317.     
  318.     frame.left += hPixelDelta;
  319.     frame.right += hPixelDelta;
  320.     frame.top += vPixelDelta;
  321.     frame.bottom += vPixelDelta;
  322.     
  323.     aperture.left += hPixelDelta;
  324.     aperture.right += hPixelDelta;
  325.     aperture.top += vPixelDelta;
  326.     aperture.bottom += vPixelDelta;
  327.     
  328.     
  329.         /*
  330.          * Notify subpanes, if any, that this view has scrolled.
  331.          */
  332.         
  333.     if (itsSubviews != NULL) {
  334.         LongPt offset;
  335.         offset.h = hPixelDelta;
  336.         offset.v = vPixelDelta;
  337.         itsSubviews->DoForEach1((EachFunc1) Pane_EnclosureScrolled, (long) &offset);
  338.     }
  339.     
  340.     
  341.         /*
  342.          * If:
  343.          *     • this pane wants to be avoided,
  344.          * and • this pane is enclosed by a CScrollorama that wants to avoid,
  345.          * and • this pane wants a specific area to be avoided (as opposed
  346.          *       to just wanting to avoid its whole aperture),
  347.          * then:
  348.          * the enclosure's paneVisRgn is out of date, and needs to be
  349.          * marked as such.
  350.          */
  351.         
  352.     if (beAvoided
  353.         && member(itsEnclosure, CScrollorama)
  354.         && ((CScrollorama*)itsEnclosure)->getAvoidSubscrolloramas()
  355.         && avoidedRgn != NULL) {
  356.         
  357.         ((CScrollorama*)itsEnclosure)->markPaneVisRgnAsOutOfDate();
  358.         
  359.     }
  360.     
  361.     
  362.         /*
  363.          * If this pane clips to its avoided region, then it is now
  364.          * out of date and needs to be marked as so.
  365.          */
  366.         
  367.     if (clipToAvoidedRgn) {
  368.         markPaneVisRgnAsOutOfDate();
  369.     }
  370.     
  371.     
  372.         /*
  373.          * If an immediate redraw was requested, tell the CWindow
  374.          * to update itself.
  375.          */
  376.         
  377.     if (redraw) {
  378.         ( (CWindow *) ((WindowPeek) macPort)->refCon )->Update();
  379.     }
  380. }
  381.  
  382.  
  383.     
  384. void CScrollorama::SetBounds(LongRect *aBounds)
  385. {
  386.         /*
  387.          * Mårten Sörliden's "if the bounds shrinks, keep the frame
  388.          * inside it" bug fix (marten@uidesign.se).
  389.          */
  390.         
  391.     long hDelta, vDelta;
  392.     
  393.     hDelta = 0;
  394.     vDelta = 0;
  395.     
  396.     if (aBounds->right < frame.right)
  397.         hDelta = Min(frame.left - aBounds->left, frame.right - aBounds->right);
  398.     
  399.     if (aBounds->bottom < frame.bottom)
  400.         vDelta = Min(frame.top - aBounds->top, frame.bottom - aBounds->bottom);
  401.     
  402.     if (hDelta != 0 || vDelta != 0) {
  403.         Scroll(-hDelta, -vDelta, FALSE);
  404.     }
  405.     
  406.     inherited::SetBounds(aBounds);
  407. }
  408.  
  409.  
  410.  
  411. void CScrollorama::setAvoidSubscrolloramas(Boolean newAvoidSubscrolloramas)
  412. {
  413.     if (newAvoidSubscrolloramas == avoidSubscrolloramas) return;
  414.     avoidSubscrolloramas = (newAvoidSubscrolloramas != FALSE);
  415.     if (itsSubviews != NULL) {
  416.         markPaneVisRgnAsOutOfDate();
  417.     }
  418. }
  419.  
  420.  
  421.  
  422. Boolean CScrollorama::getAvoidSubscrolloramas(void)
  423. {
  424.     return avoidSubscrolloramas;
  425. }
  426.  
  427.  
  428.  
  429. void CScrollorama::setBeAvoided(Boolean newBeAvoided)
  430. {
  431.     if (beAvoided == newBeAvoided) return;
  432.     beAvoided = (newBeAvoided != FALSE);
  433.     if (member(itsEnclosure, CScrollorama)) {
  434.         ((CScrollorama*)itsEnclosure)->markPaneVisRgnAsOutOfDate();
  435.     }
  436. }
  437.  
  438.  
  439.  
  440. Boolean CScrollorama::getBeAvoided(void)
  441. {
  442.     return beAvoided;
  443. }
  444.  
  445.  
  446.  
  447. void CScrollorama::setClipToAvoidedRgn(Boolean newClipToAvoidedRgn)
  448. {
  449.     if (clipToAvoidedRgn == newClipToAvoidedRgn) return;
  450.     clipToAvoidedRgn = (newClipToAvoidedRgn != FALSE);
  451.     if (avoidedRgn != NULL) {
  452.         markPaneVisRgnAsOutOfDate();
  453.     }
  454. }
  455.  
  456.  
  457.  
  458. Boolean CScrollorama::getClipToAvoidedRgn(void)
  459. {
  460.     return clipToAvoidedRgn;
  461. }
  462.  
  463.  
  464.  
  465. void CScrollorama::setAvoidedRgn(RgnHandle newAvoidedRgn)
  466. {
  467.     if (newAvoidedRgn == avoidedRgn) return;
  468.     
  469.     forgetAvoidedRgn();
  470.     
  471.     if (newAvoidedRgn != NULL) {
  472.         
  473.             /*
  474.              * Make sure we don't try to avoid drawing things that are
  475.              * outside our bounds.
  476.              */
  477.         
  478.         Rect myBounds;
  479.         RgnHandle avoidWithinBoundsRgn;
  480.         
  481.         avoidWithinBoundsRgn = NewRgn();
  482.         LongToQDRect(&bounds, &myBounds);
  483.         RectRgn(avoidWithinBoundsRgn, &myBounds);
  484.         SectRgn(avoidWithinBoundsRgn, newAvoidedRgn, avoidWithinBoundsRgn);
  485.         
  486.         avoidedRgn = avoidWithinBoundsRgn;
  487.         
  488.     }
  489.     
  490.     markPaneVisRgnAsOutOfDate();
  491. }
  492.  
  493.  
  494.  
  495.  
  496. void CScrollorama::getAvoidedRgn(RgnHandle theAvoidedRgn)
  497. {
  498.     if (avoidedRgn == NULL) {
  499.         
  500.             /*
  501.              * A NULL avoidedRgn means "avoid everything."
  502.              */
  503.         
  504.         Rect myBounds;
  505.         LongToQDRect(&bounds, &myBounds);
  506.         RectRgn(theAvoidedRgn, &myBounds);
  507.         
  508.     } else {
  509.         
  510.         CopyRgn(avoidedRgn, theAvoidedRgn);
  511.         
  512.     }
  513. }
  514.  
  515.  
  516.  
  517. void CScrollorama::markPaneVisRgnAsOutOfDate(void)
  518. {
  519.     pvrIsUpToDate = FALSE;
  520. }
  521.  
  522.  
  523.  
  524. Boolean CScrollorama::getPaneVisRgnIsUpToDate(void)
  525. {
  526.     return pvrIsUpToDate;
  527. }
  528.  
  529.  
  530.  
  531.     void doRemoveFromRgn(CView *theSubview, long theNewPaneVisRgn);
  532.     void doRemoveFromRgn(CView *theSubview, long theNewPaneVisRgn)
  533.     {
  534.         ASSERT(member(theSubview, CPane));
  535.         if (member(theSubview, CScrollorama)
  536.             && ((CScrollorama*)theSubview)->getBeAvoided()) {
  537.             
  538.             RgnHandle theAvoidedRgn;
  539.             RgnHandle theApertureRgn;
  540.             LongRect theApertureL;
  541.             Rect theAperture;
  542.             
  543.             theAvoidedRgn = NewRgn();
  544.             ((CScrollorama*)theSubview)->getAvoidedRgn(theAvoidedRgn);
  545.             
  546.                 /*
  547.                  * A subscrollorama can't make its enclosure avoid anything
  548.                  * that's not in the subpane's aperture.
  549.                  */
  550.             theApertureRgn = NewRgn();
  551.             ((CPane*)theSubview)->GetAperture(&theApertureL);
  552.             LongToQDRect(&theApertureL, &theAperture);
  553.             RectRgn(theApertureRgn, &theAperture);
  554.             SectRgn(theAvoidedRgn, theApertureRgn, theAvoidedRgn);
  555.             DisposeRgn(theApertureRgn);
  556.             
  557.                 /*
  558.                  * Change the subpane's avoided region into the enclosure's
  559.                  * frame coordinate system.
  560.                  */
  561.             OffsetRgn(theAvoidedRgn,
  562.                 ((CPane*)theSubview)->hEncl,
  563.                 ((CPane*)theSubview)->vEncl);
  564.             
  565.                 /*
  566.                  * Subtract its area out from the enclosure's visible region.
  567.                  */
  568.             DiffRgn((RgnHandle) theNewPaneVisRgn,
  569.                 theAvoidedRgn,
  570.                 (RgnHandle) theNewPaneVisRgn);
  571.             
  572.             DisposeRgn(theAvoidedRgn);
  573.             
  574.         }
  575.     }
  576.     
  577. void CScrollorama::updatePaneVisRgn(void)
  578. {
  579.     Rect theApertureRect;
  580.     
  581.     if (getPaneVisRgnIsUpToDate()) return;
  582.     
  583.     forgetPaneVisRgn();
  584.     
  585.     LongToQDRect(&aperture, &theApertureRect);
  586.     
  587.     if (EmptyRect(&theApertureRect)) {
  588.         
  589.             /*
  590.              * Leave the instance var "paneVisRgn" set to NULL.  NULL means
  591.              * "the whole aperture is visible," which, if the aperture is
  592.              * an empty rectangle, is surely true.
  593.              */
  594.         
  595.     } else {
  596.         
  597.         RgnHandle theApertureRgn;
  598.         RgnHandle theNewPaneVisRgn;
  599.         
  600.         theApertureRgn = NewRgn();
  601.         theNewPaneVisRgn = NewRgn();
  602.         RectRgn(theApertureRgn, &theApertureRect);
  603.         CopyRgn(theApertureRgn, theNewPaneVisRgn);
  604.         
  605.         if (itsSubviews != NULL) {
  606.             itsSubviews->DoForEach1(doRemoveFromRgn, (long) theNewPaneVisRgn);
  607.         }
  608.         
  609.         if (getClipToAvoidedRgn() && avoidedRgn != NULL) {
  610.             SectRgn(theNewPaneVisRgn, avoidedRgn, theNewPaneVisRgn);
  611.         }
  612.         
  613.         if (EqualRgn(theNewPaneVisRgn, theApertureRgn)) {
  614.                 /*
  615.                  * If the new paneVisRgn would just be the entire aperture--i.e.
  616.                  * if there's no special clipping going on--just leave the
  617.                  * instance variable set to NULL.
  618.                  */
  619.             DisposeRgn(theNewPaneVisRgn);
  620.         } else {
  621.             paneVisRgn = theNewPaneVisRgn;
  622.         }
  623.         
  624.         DisposeRgn(theApertureRgn);
  625.         
  626.     }
  627.     
  628.     pvrIsUpToDate = TRUE;
  629. }
  630.  
  631.  
  632.  
  633. void CScrollorama::Hide(void)
  634. {
  635.     inherited::Hide();
  636.     if (member(itsEnclosure, CScrollorama)) {
  637.         ((CScrollorama*)itsEnclosure)->markPaneVisRgnAsOutOfDate();
  638.     }
  639. }
  640.  
  641.  
  642.  
  643. void CScrollorama::Show(void)
  644. {
  645.     inherited::Show();
  646.     if (member(itsEnclosure, CScrollorama)) {
  647.         ((CScrollorama*)itsEnclosure)->markPaneVisRgnAsOutOfDate();
  648.     }
  649. }
  650.  
  651.  
  652.  
  653. void CScrollorama::AddSubview(CView *theSubview)
  654. {
  655.     inherited::AddSubview(theSubview);
  656.     if (member(theSubview, CScrollorama)) {
  657.         markPaneVisRgnAsOutOfDate();
  658.     }
  659. }
  660.  
  661.  
  662.  
  663. void CScrollorama::RemoveSubview(CView *theSubview)
  664. {
  665.     inherited::RemoveSubview(theSubview);
  666.     if (member(theSubview, CScrollorama)) {
  667.         markPaneVisRgnAsOutOfDate();
  668.     }
  669. }
  670.  
  671.  
  672.  
  673. void CScrollorama::Offset(long hOffset, long vOffset, Boolean redraw)
  674. {
  675.     inherited::Offset(hOffset, vOffset, redraw);
  676.     if (member(itsEnclosure, CScrollorama)) {
  677.         ((CScrollorama*)itsEnclosure)->markPaneVisRgnAsOutOfDate();
  678.     }
  679. }
  680.  
  681.  
  682.  
  683. void CScrollorama::ChangeSize(Rect *delta, Boolean redraw)
  684. {
  685.     inherited::ChangeSize(delta, redraw);
  686.     if (member(itsEnclosure, CScrollorama)) {
  687.         ((CScrollorama*)itsEnclosure)->markPaneVisRgnAsOutOfDate();
  688.     }
  689. }
  690.  
  691.  
  692.  
  693.     /*
  694.      * This method is the same as CPane::DrawAll(), but with two lines
  695.      * of code #if'fed out.
  696.      */
  697.     
  698. void CScrollorama::DrawAll(Rect *area)
  699. {
  700.     Rect    tmpArea = *area;
  701.     
  702.     Prepare();
  703.     
  704.     /* area is in Window coordinates, put it into Frame or QD coordinates    */
  705.  
  706.     if (usingLongCoord)
  707.         OffsetRect( &tmpArea, thePort->portRect.left, thePort->portRect.top);
  708.     else
  709.         OffsetRect( &tmpArea, hOrigin, vOrigin);
  710.     
  711. #if 0
  712.         /*
  713.          * At this point, CPane would decide to force the port's clipRgn
  714.          * to the full area that's being drawn.  CScrollorama wants to do
  715.          * something else, though, which is why this code has been
  716.          * #if'fed out.
  717.          */
  718.     if (!printing) {    /* no need to SectRect here, already done in Pane_Draw */
  719.  
  720.         ClipRect( &tmpArea);
  721.     }
  722. #else
  723.     if (!printing) {
  724.             /*
  725.              * We only want to draw into the _intersection_ of the requested
  726.              * rectangle and the paneVisRgn.  The port's clipRgn has been
  727.              * set to the paneVisRgn in CScrollorama::Prepare().
  728.              */
  729.         RgnHandle drawAreaRgn;
  730.         drawAreaRgn = NewRgn();
  731.         RectRgn(drawAreaRgn, &tmpArea);
  732.         SectRgn(macPort->clipRgn, drawAreaRgn, macPort->clipRgn);
  733.         DisposeRgn(drawAreaRgn);
  734.     }
  735. #endif
  736.  
  737.     Draw( &tmpArea);
  738.                 
  739.     if (itsSubviews != NULL)
  740.     {
  741.         // clip area to aperture of this view before drawing subviews
  742.         
  743.         if (!printing)
  744.         {
  745.             FrameToWindR( &aperture, &tmpArea);
  746.             SectRect( &tmpArea, area, &tmpArea);
  747.         }
  748.         else            /* TCL 1.1.2 DLP 10/28/91 */
  749.             tmpArea = *area;
  750.             
  751.         itsSubviews->DoForEach1((EachFunc1) Pane_Draw, (long) &tmpArea);
  752.     }
  753. }
  754.  
  755.  
  756.  
  757. void CScrollorama::Prepare()
  758. {
  759.         /*
  760.          * The inherited method, CPane::Prepare(), sets the clipping region
  761.          * to the aperture of this pane.
  762.          */
  763.     inherited::Prepare();
  764.     
  765.     if (getAvoidSubscrolloramas() || getClipToAvoidedRgn()) {
  766.         
  767.             /*
  768.              * OK, we need to go a bit further.  Update the paneVisRgn,
  769.              * if it isn't already, and then get the intersection of
  770.              * that with the aperture.
  771.              */
  772.              
  773.         updatePaneVisRgn();
  774.         if (paneVisRgn != NULL) {
  775.             SectRgn(macPort->clipRgn, paneVisRgn, macPort->clipRgn);
  776.         }
  777.         
  778.     }
  779. }
  780.  
  781.  
  782.  
  783. /********************************/
  784.  
  785.  
  786.  
  787. void CScrollorama::forgetPaneVisRgn(void)
  788. {
  789.     if (paneVisRgn != NULL) {
  790.         DisposeRgn(paneVisRgn);
  791.         paneVisRgn = NULL;
  792.     }
  793. }
  794.  
  795.  
  796.  
  797. void CScrollorama::forgetAvoidedRgn(void)
  798. {
  799.     if (avoidedRgn != NULL) {
  800.         DisposeRgn(avoidedRgn);
  801.         avoidedRgn = NULL;
  802.     }
  803. }
  804.  
  805.  
  806.  
  807. /********************************/
  808.  
  809.  
  810.  
  811. void nonErasingScrollRect(Rect *srcArea, short hDelta, short vDelta, RgnHandle updateRgn)
  812. {
  813.     Rect destArea;
  814.     RgnHandle destRgn;
  815.     destArea = *srcArea;
  816.     OffsetRect(&destArea, hDelta, vDelta);
  817.     CopyBits(&thePort->portBits, &thePort->portBits,
  818.         srcArea, &destArea,
  819.         srcCopy, NULL);
  820.     RectRgn(updateRgn, srcArea);
  821.     destRgn = NewRgn();
  822.     RectRgn(destRgn, &destArea);
  823.     DiffRgn(updateRgn, destRgn, updateRgn);
  824.     DisposeRgn(destRgn);
  825.         /*
  826.          * ...and then _don't_ EraseRgn(updateRgn).  I believe
  827.          * that to be the only logical difference between this
  828.          * code and _ScrollRect.
  829.          */
  830. }
  831.